/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	Geometry.cpp
*
*	Comments	-	See Geometry.h
*
**************************************************************************************/
#include "../Include/Geometry.h"
#include "../Include/GraphicsResourceManager.h"
#include "../Include/Engine.h"
#include "../Include/XMLParser.h"
#include "../Include/FileSystem.h"
#include "../Include/ResourceCache.h"
#include "../Include/GeometryElementInfo.h"
#include "../Include/Tokenizer.h"

namespace Pulse
{
	GeometryDesc::GeometryDesc( void )
	{
		ConstructorDefaultParams();
	}

	GeometryDesc::GeometryDesc( const CHAR *pFilename ) 
	{
		ConstructorDefaultParams();
		SetToLoad( pFilename ); 
	}

	GeometryDesc::~GeometryDesc( void )
	{
		if ( IsStreamSourcesManaged() )
		{
			// Delete stream (vertex and index) sources
			for ( SIZE_T i = 0; i < m_vertexSources.GetSize(); ++i )
				PSX_SafeDelete( m_vertexSources[i] );

			m_vertexSources.Clear();
			PSX_SafeDelete( m_pIndexSource );
		}
	}

	//void GeometryDesc::SetGeometry( ETopology::Type topology, VertexBuffer*pVB, IndexBuffer *pIB,
	//	UINT numGeoSubsets, GeometrySubset *pSubsets, EPipelineExecutor::Type executor )
	//{

	//}

	EErrorCode::Type GeometryDesc::AddVertexSourceType( EVertexElement::Type type, SIZE_T32 numElements )
	{
		// Make sure the stream type is empty
		for ( SIZE_T i = 0; i < m_vertexSources.GetSize(); ++i )
			if ( m_vertexSources[i]->GetType() == type )
			{
				PSX_PushError( "Vertex type already exists." );
				return EErrorCode::LOGIC;
			}

		VertexSource *pSource = new VertexSource( type, numElements );
		m_vertexSources.PushBack( pSource );

		return EErrorCode::OKAY;
	}

	EErrorCode::Type GeometryDesc::AddIndexSource( SIZE_T32 numIndices )
	{
		if ( m_pIndexSource )
		{
			PSX_PushError( "Index source already exists." );
			return EErrorCode::LOGIC;
		}

		// Check if we should be using a 16 or 32 bit indices
		BOOL bUse16BitIndices = TRUE;
		VertexSource *pVSource = GetVertexSource( EVertexElement::POSITION );

		if ( pVSource )
		{
			if( pVSource->GetElementCount() > PSX_USHORT_MAX )
			{
				bUse16BitIndices = FALSE;
			}
		}

		m_pIndexSource = new IndexSource( numIndices, bUse16BitIndices );
		
		return EErrorCode::OKAY;
	}

	VertexSource * GeometryDesc::GetVertexSource( EVertexElement::Type type )
	{
		for ( SIZE_T i = 0; i < m_vertexSources.GetSize(); ++i )
			if ( m_vertexSources[i]->GetType() == type )
				return m_vertexSources[i];

		return PSX_NULL;
	}

	const VertexSource * GeometryDesc::GetVertexSource( EVertexElement::Type type ) const
	{
		for ( SIZE_T i = 0; i < m_vertexSources.GetSize(); ++i )
			if ( m_vertexSources[i]->GetType() == type )
				return m_vertexSources[i];

		return PSX_NULL;
	}

	void GeometryDesc::AddGeometrySubset( UINT32 numPrimitives, UINT32 indicesOffset )
	{
		GeometrySubset subset;
		subset.m_indicesOffset = indicesOffset;
		subset.m_numPrimitives = numPrimitives;

		m_geometrySubsets.PushBack( subset );
	}

	void GeometryDesc::Cleanup( void )
	{
		m_topologyType = ETopology::TRIANGLE_LIST;
		m_geometrySubsets.Clear();

		m_filename.Clear();

		if ( IsStreamSourcesManaged() )
		{
			m_bManageStreamSources = FALSE;

			// Delete stream (vertex and index) sources
			for ( SIZE_T i = 0; i < m_vertexSources.GetSize(); ++i )
				PSX_SafeDelete( m_vertexSources[i] );
		}

		m_vertexSources.Clear();
		PSX_SafeDelete( m_pIndexSource );
	}

	void GeometryDesc::ConstructorDefaultParams( void )
	{
		m_topologyType = ETopology::TRIANGLE_LIST;
		m_bManageStreamSources = FALSE;
		m_pIndexSource = PSX_NULL;
	}

	// Geometry
	Geometry::Geometry( void )
	{

	}

	Geometry::~Geometry( void )
	{

	}

	BOOL Geometry::CreateResource( BaseResDesc *pDesc )
	{
		if ( pDesc->GetType() != GetType() )
			return FALSE;

		m_desc = *((GeometryDesc*)pDesc);
		m_desc.SetManageStreamSource( TRUE );

		if ( PerformInitialize( m_desc.IsAsyncLoad() ) == EErrorCode::OKAY )
			SetFlagCreated();

		return IsCreated();
	}
	
	BOOL Geometry::DestroyResource( void )
	{
		UnloadResource();
		SetFlagDestroyed();	
		return TRUE;	
	}
	
	BOOL Geometry::LoadResource( void )
	{
		if ( Initialize() == EErrorCode::OKAY )
		{
			SetFlagLoaded();	
			return TRUE;	
		}

		return FALSE;
	}

	BOOL Geometry::UnloadResource( void )
	{
		Cleanup();
		SetFlagUnloaded();
		return TRUE;	
	}

	EErrorCode::Type Geometry::Initialize( void )
	{
		// HACK: Forcing to use triangle list for now.
		m_desc.m_topologyType = ETopology::TRIANGLE_LIST;

		// Load filename?
		if ( m_desc.m_filename.IsEmpty() == FALSE )
		{
			String fullPath = PSX_PATH_GEOMETRY + m_desc.m_filename;
			XMLDocumentPtr pDoc = XMLParser::Load( fullPath.GetBuffer() );
		
			if ( pDoc.IsNull() )
			{
				PSX_PushError( "Failed to load geometry file." );
				return EErrorCode::FILE_NOT_FOUND;
			}

			XMLElementPtr pElem = pDoc->GetFirstChild();

			if ( pElem.IsNull() == FALSE && pElem->GetName() == PSX_String("Geometry") )
			{
				ProcessGeometry( pElem );
			}
			else
			{
				PSX_PushError( "Invalid geometry file." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_pIndexBuffer = PSX_NULL;

		}
		else
		{
			// TODO: Manual loading

			// Hack set to triangle list for now.
			m_desc.m_topologyType = ETopology::TRIANGLE_LIST;

			m_pIndexBuffer = PSX_NULL;

		}

		// We'll lazily evaluate what buffers to create
		// Create vertex and index buffers
		//CreateGraphicsBuffers();

		return EErrorCode::OKAY;
	}

	void Geometry::Cleanup( void )
	{
		for ( SIZE_T i = 0; i < m_techRenderInfos.GetSize(); ++i )
		{
			delete m_techRenderInfos[i];
		}

		m_techRenderInfos.Clear();

		VertexTypeBufferMap::Iterator iter = m_vertexTypeBufferMap.IteratorBegin();
		VertexTypeBufferMap::Iterator iterEnd = m_vertexTypeBufferMap.IteratorEnd();

		while ( iter != iterEnd )
		{
			PSX_SafeRelease( iter->second );
			++iter;
		}

		m_vertexTypeBufferMap.Clear();

		PSX_SafeRelease( m_pIndexBuffer );
	}

	EErrorCode::Type Geometry::CreateGraphicsBuffers( void )
	{
		GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();
		SIZE_T numVertexSources = m_desc.m_vertexSources.GetSize();

		// Create Vertex Buffers
		for ( SIZE_T i = 0; i < numVertexSources ; ++i )
		{
			VertexBufferDesc desc;
			VertexSource *pSource = m_desc.m_vertexSources[i];
			VertexBuffer *pBuffer;

			desc.SetAsStaticVertexBuffer( pSource->GetElementSize(), 
				pSource->GetElementCount(), pSource->GetBuffer() );

			pBuffer = pGM->CreateVertexBuffer( &desc );

			if ( pBuffer )
			{
				m_vertexTypeBufferMap[pSource->GetType()] = pBuffer; 
			}
			else
			{
				Cleanup();
				return EErrorCode::GRAPHICS;
			}
		}

		// Create index buffer
		IndexSource *pIndexSource = m_desc.m_pIndexSource;
		IndexBufferDesc desc;
		desc.SetAsStaticIndexBuffer( pIndexSource->GetNumIndices(), pIndexSource->GetBuffer(), pIndexSource->Is16BitIndices() );

		m_pIndexBuffer = pGM->CreateIndexBuffer( &desc );

		if ( m_pIndexBuffer == PSX_NULL )
			return EErrorCode::GRAPHICS;
		
		return EErrorCode::OKAY;
	}

	TechGeoRenderInfo * Geometry::CreateTechGeoRenderInfo( RenderTechnique *pTech )
	{
		if ( pTech == PSX_NULL )
			return PSX_NULL;

		// Make sure the info doesn't exist
		{
			TechGeoRenderInfo *pFindInfo = FindTechniqueRenderInfo( pTech->GetDescription()->m_filename.GetBuffer() );
		
			if ( pFindInfo )
			{
				PSX_PushWarning( "TechGeoRenderInfo already exists. Skipping creation." );
				return pFindInfo;
			}
		}

		// It doesn't exist. Create new input layout
		// Build the vertex buffer and create the input layout
		// we create the input layout based on the technique's render-pass' geometry requirements.
		GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();
		TechGeoRenderInfo *pNewInfo = PSX_NULL;
		const SIZE_T numPasses = pTech->GetNumRenderPasses();

		pNewInfo = new TechGeoRenderInfo;
		pNewInfo->m_techniqueName = pTech->GetDescription()->m_filename;
		pNewInfo->m_renderPassInfos.Reserve( numPasses );

		for ( SIZE_T i = 0; i < numPasses; ++i )
		{
			RenderPass *pPass = pTech->GetRenderPass( i );
			SIZE_T numGeometryRequirements = pPass->GetNumGeometryRequirements();
			GeometryElementRequirement *pGeoRequirements = pPass->GetGeometryRequirements();
			RenderPassRenderInfo *pRenderPassInfo;
			InputLayoutDesc desc;

			if ( numGeometryRequirements == 0 )
			{
				PSX_PushWarning( "Technique has no geometry requirements. Skipping creation." );
				return PSX_NULL;
			}

			pRenderPassInfo = new RenderPassRenderInfo;
			pRenderPassInfo->m_vertexBuffers.Reserve( numGeometryRequirements );

			for ( SIZE_T j = 0; j < numGeometryRequirements; ++j )
			{
				// Get Vertex Buffer
				GeometryElementRequirement *pGeoReq = &pGeoRequirements[j];

				VertexBuffer *pVB = GetVertexBuffer( pGeoReq->m_type );

				if ( pVB == PSX_NULL )
				{
					PSX_PushWarning( "Missing vertex buffer requirement." );
					delete pRenderPassInfo;
					return PSX_NULL;
				}

				pRenderPassInfo->m_vertexBuffers.PushBack( pVB );

				// Build input layout
				desc.AddElementAsPerVertexData( GeometryElementInfo::GetVertexSemanticName(pGeoReq->m_type),
					0, GeometryElementInfo::GetVertexGraphicsFormat(pGeoReq->m_type), (UINT)j, 0 );
			}

			// Finally, create our input layout
			Shader *pShader = pTech->GetRenderPass(i)->GetShader( EShader::VERTEX );
			desc.SetShaderForLayoutSignature( pShader );
			pRenderPassInfo->m_pInputLayout = pGM->CreateInputLayout( &desc ); 

			PSX_SafeRelease( pShader );

			if ( pRenderPassInfo->m_pInputLayout == PSX_NULL )
			{
				PSX_PushWarning( "Failed to create input layout." );
				delete pRenderPassInfo;
				return PSX_NULL;
			}

			pNewInfo->m_renderPassInfos.PushBack( pRenderPassInfo );

		}

		m_techRenderInfos.PushBack( pNewInfo );

		return pNewInfo;
	}

	TechGeoRenderInfo * Geometry::GetTechniqueRenderInfo( RenderTechnique *pTech )
	{
		TechGeoRenderInfo *pInfo = FindTechniqueRenderInfo( pTech->GetDescription()->m_filename.GetBuffer() );
	
		if ( pInfo )
			return pInfo;

		pInfo = CreateTechGeoRenderInfo( pTech );

		if ( pInfo )
		{
			return pInfo;
		}

		return PSX_NULL;
	}

	TechGeoRenderInfo * Geometry::FindTechniqueRenderInfo( const CHAR *pTechName )
	{
		for ( SIZE_T i = 0; i < m_techRenderInfos.GetSize(); ++i )
		{
			TechGeoRenderInfo *pInfo = m_techRenderInfos[i];
			
			if ( pInfo->m_techniqueName == pTechName )
			{
				return pInfo;
			}
		}

		return PSX_NULL;
	}

	IndexBuffer * Geometry::GetIndexBuffer( void )
	{
		if ( m_pIndexBuffer )
		{
			m_pIndexBuffer->AddRef();
			return m_pIndexBuffer;
		}

		// Create index buffer
		IndexSource *pIndexSource = m_desc.m_pIndexSource;

		if ( pIndexSource )
		{
			GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();
			IndexBufferDesc desc;
			desc.SetAsStaticIndexBuffer( pIndexSource->GetNumIndices(), pIndexSource->GetBuffer(), pIndexSource->Is16BitIndices() );
			m_pIndexBuffer = pGM->CreateIndexBuffer( &desc );

			if ( m_pIndexBuffer )
			{
				m_pIndexBuffer->AddRef();
				return m_pIndexBuffer;
			}
		}

		return PSX_NULL;
	}

	const GeometrySubset * Geometry::GetGeometrySubset( UPOS_T index )
	{
		if ( index < m_desc.GetNumGeometrySubsets() )
		{
			return m_desc.GetGeometrySubset( index );
		}
		else
		{
			return PSX_NULL;
		}
	}

	VertexBuffer * Geometry::GetVertexBuffer( EVertexElement::Type type )
	{
		VertexTypeBufferMap::Iterator iter = m_vertexTypeBufferMap.Find( type );

		if ( iter != m_vertexTypeBufferMap.IteratorEnd() )
		{
			iter->second->AddRef();
			return iter->second;
		}

		// Check if we have it in our vertex stream
		VertexSource *pSource = m_desc.GetVertexSource( type );

		if ( pSource == PSX_NULL )
			return PSX_NULL;

		// We have the vertex source but the vertex buffer hasn't been create
		//	yet. So create the vertex buffer.
		GraphicsResourceManager *pGM = GraphicsResourceManager::GetInstance();
		VertexBufferDesc desc;
		VertexBuffer *pBuffer;

		desc.SetAsStaticVertexBuffer( pSource->GetElementSize(), 
			pSource->GetElementCount(), pSource->GetBuffer() );

		pBuffer = pGM->CreateVertexBuffer( &desc );

		if ( pBuffer )
		{
			m_vertexTypeBufferMap[type] = pBuffer;
			pBuffer->AddRef();
			return pBuffer;
		}

		return PSX_NULL;
	}

	BOOL Geometry::IsVertexElementAvailable( EVertexElement::Type type )
	{
		for ( SIZE_T i = 0; i < m_desc.m_vertexSources.GetSize(); ++i )
		{
			if ( m_desc.m_vertexSources[i]->GetType() ==  type )
				return TRUE;
		}

		return FALSE;
	}

	//InputLayout * Geometry::GetInputLayout( Effect *pEffect )
	//{
	//	RenderTechnique *pTech = pEffect->GetTechnique();

	//	if ( pTech )
	//	{
	//		InputLayout *pIL = GetInputLayout( pTech );

	//		pTech->Release();
	//	
	//		// NOTE: We don't call addref since the GetInputLayout(RenderTechnique)
	//		//	already calls addref. This is just a wrapper function.
	//		return pIL;
	//	}

	//	return PSX_NULL;
	//}

	//InputLayout * Geometry::GetInputLayout( RenderTechnique *pTech )
	//{
	//	if ( pTech == PSX_NULL )
	//		return PSX_NULL;

	//	String name = pTech->GetDescription()->m_filename;

	//	// Search if we have the techique-input layout already available
	//	for ( SIZE_T i =  0; i < m_techRenderInfos.GetSize(); ++i )
	//	{
	//		TechGeoRenderInfo *pMap = m_techRenderInfos[i];

	//		if ( pMap->m_techniqueName == name )
	//		{
	//			pMap->m_pInputLayout->AddRef();
	//			return pMap->m_pInputLayout;
	//		}
	//	}

	//	// It doesn't exist. Create new input layout
	//	TechGeoRenderInfo *pNewInfo = CreateTechGeoRenderInfo( pTech );

	//	if ( pNewInfo == PSX_NULL )
	//	{
	//		return PSX_NULL;
	//	}

	//	pNewInfo->m_pInputLayout->AddRef();
	//	return pNewInfo->m_pInputLayout;
	//}

	EErrorCode::Type Geometry::ProcessGeometry( XMLElementPtr pElem )
	{
		EErrorCode::Type retCode;
		XMLElementPtr pChild = pElem->GetFirstChild();

		while ( pChild.IsNull() == FALSE )
		{

			if ( pChild->GetName() == PSX_String("Info") )
				retCode = ProcessInfo( pChild );
			else if ( pChild->GetName() == PSX_String("VertexStream") )
				retCode = ProcessVertexStream( pChild );
			else if ( pChild->GetName() == PSX_String("IndexStream") )
				retCode = ProcessIndexStream( pChild );
			else if ( pChild->GetName() == PSX_String("SubGeometryStream") )
				retCode = ProcessSubGeometryStream( pChild );
			else
				retCode = EErrorCode::UNKNOWN;

			if ( retCode != EErrorCode::OKAY && retCode != EErrorCode::UNKNOWN )
			{
				return EErrorCode::_ERROR;
			}
			else if ( retCode == EErrorCode::UNKNOWN )
			{
				PSX_PushWarning( "Unknown info tag %s. Skipping this tag.", pChild->GetName().GetBuffer() );
			}

			pChild = pChild->GetNextSibling();
		}

		return EErrorCode::OKAY;
	}

	EErrorCode::Type Geometry::ProcessInfo( XMLElementPtr pElem )
	{
		return EErrorCode::OKAY;
	}

	EErrorCode::Type Geometry::ProcessVertexStream( XMLElementPtr pElem )
	{
		XMLElementPtr pChild = pElem->GetFirstChild();
		String name;
		String buffer;
		SIZE_T32 count;
		String streamString;
		VertexSource *pSource;
		EVertexElement::Type elementType;

		while ( pChild.IsNull() == FALSE )
		{
			name = pChild->GetName();

			// determine what type of vertex element this is
			if ( name == GeometryElementInfo::GetVertexName( EVertexElement::POSITION ) )
			{
				elementType = EVertexElement::POSITION;

				// Create Position
				buffer		= pChild->FindChild(PSX_String("Count") )->GetValue();
				count		= buffer.ToSIZE_T32();
				streamString = pChild->FindChild(PSX_String("Elements"))->GetValue();
				
				pSource = new VertexSource( elementType, count );
				m_desc.m_vertexSources.PushBack( pSource );
			
				// Tokenize the vertex list string
				String tokenString;
				Vector3 position;
				UPOS_T tokenMarker = 0;

				for ( SIZE_T32 i = 0; i < count; ++i )
				{
					// Get x, y, z pos
					for ( SIZE_T32 j = 0; j < 3; ++j )
					{
						if ( !Tokenizer::NextToken( streamString.GetBuffer(), &tokenMarker, &tokenString ) )
						{
							// ERROR. It shouldn't enter here!!!
							PSX_PushError( "Incomplete vertex position list! Every entry should contain 3 float values!" );
							return EErrorCode::INVALID_FORMAT;
						}

						position[j] = tokenString.ToFLOAT();
					}
					pSource->GetAsPositions()[i] = position;
				}
			}
			else if ( name == GeometryElementInfo::GetVertexName( EVertexElement::NORMAL ) )
			{
				elementType = EVertexElement::NORMAL;

				// Create normals
				buffer		= pChild->FindChild(PSX_String("Count") )->GetValue();
				count		= buffer.ToSIZE_T32();
				streamString = pChild->FindChild(PSX_String("Elements"))->GetValue();
				
				pSource = new VertexSource( elementType, count );
				m_desc.m_vertexSources.PushBack( pSource );
			
				// Tokenize the list string
				String tokenString;
				Vector3 normal;
				UPOS_T tokenMarker = 0;

				for ( SIZE_T32 i = 0; i < count; ++i )
				{
					// Get x, y, z normal
					for ( SIZE_T32 j = 0; j < 3; ++j )
					{
						if ( !Tokenizer::NextToken( streamString.GetBuffer(), &tokenMarker, &tokenString ) )
						{
							// ERROR. It shouldn't enter here!!!
							PSX_PushError( "Incomplete normal list! Every entry should contain 3 float values!" );
							return EErrorCode::INVALID_FORMAT;
						}

						normal[j] = tokenString.ToFLOAT();
					}
					pSource->GetAsNormals()[i] = normal;
				}
			}
			else if ( name == GeometryElementInfo::GetVertexName( EVertexElement::TEXTURE_DIFFUSE ) )
			{
				elementType = EVertexElement::TEXTURE_DIFFUSE;

				// Create normals
				buffer		= pChild->FindChild(PSX_String("Count") )->GetValue();
				count		= buffer.ToSIZE_T32();
				streamString = pChild->FindChild(PSX_String("Elements"))->GetValue();

				pSource = new VertexSource( elementType, count );
				m_desc.m_vertexSources.PushBack( pSource );

				// Tokenize the list string
				String tokenString;
				Vector2 UVDiffuse;
				UPOS_T tokenMarker = 0;

				for ( SIZE_T32 i = 0; i < count; ++i )
				{
					// Get U, V
					for ( SIZE_T32 j = 0; j < 2; ++j )
					{
						if ( !Tokenizer::NextToken( streamString.GetBuffer(), &tokenMarker, &tokenString ) )
						{
							// ERROR. It shouldn't enter here!!!
							PSX_PushError( "Incomplete normal list! Every entry should contain 2 float values!" );
							return EErrorCode::INVALID_FORMAT;
						}

						UVDiffuse[j] = tokenString.ToFLOAT();
					}
					pSource->GetAsTextureDiffuse()[i] = UVDiffuse;
				}
			}

			pChild = pChild->GetNextSibling();
		}

		return EErrorCode::OKAY;
	}

	EErrorCode::Type Geometry::ProcessIndexStream( XMLElementPtr pElem )
	{
		XMLElementPtr pChild = pElem->GetFirstChild();

		if ( pChild.IsNull() == FALSE && pChild->GetName() == GeometryElementInfo::GetIndexName() )
		{
			String buffer = pChild->FindChild(PSX_String("Count") )->GetValue();
			SIZE_T32 count = buffer.ToSIZE_T32();
			PSX_SafeDelete( m_desc.m_pIndexSource );
			IndexSource *pSource;
			
			// Use 16bit indices?
			buffer = pChild->FindChild(PSX_String("Use16Bit"))->GetValue();
			const BOOL bUse16Bit = buffer.ToBOOL();
			
			pSource = new IndexSource( count, bUse16Bit );
			
			if ( pSource == PSX_NULL )
			{
				PSX_PushError( "Out of memory." );
				return EErrorCode::MEMORY;
			}

			m_desc.m_pIndexSource = pSource;

			// Tokenize the vertex list string
			String tokenString;
			UPOS_T tokenMarker = 0;

			buffer = pChild->FindChild(PSX_String("Elements"))->GetValue();

			// Store as 16 or 32 bit indices?
			if ( pSource->Is16BitIndices() )
			{
				UINT16 index;

				for ( SIZE_T32 i = 0; i < count; ++i )
				{
					if ( !Tokenizer::NextToken( buffer.GetBuffer(), &tokenMarker, &tokenString ) )
					{
						// ERROR. It shouldn't enter here!!!
						PSX_PushError( "Incomplete index list!" );
						return EErrorCode::INVALID_FORMAT;
					}

					index = tokenString.ToUSHORT();
					pSource->GetAs16BitIndices()[i] = index;
				}
			}
			else
			{
				UINT32 index;

				for ( SIZE_T32 i = 0; i < count; ++i )
				{
					if ( !Tokenizer::NextToken( buffer.GetBuffer(), &tokenMarker, &tokenString ) )
					{
						// ERROR. It shouldn't enter here!!!
						PSX_PushError( "Incomplete index list!" );
						return EErrorCode::INVALID_FORMAT;
					}

					index = tokenString.ToUPOS_T32();
					pSource->GetAs32BitIndices()[i] = index;
				}
			}
		}

		return EErrorCode::OKAY;
	}

	EErrorCode::Type Geometry::ProcessSubGeometryStream( XMLElementPtr pElem )
	{
		XMLElementPtr pElements = pElem->FindChild(PSX_String("Elements"));
		String buffer = pElem->FindChild(PSX_String("Count"))->GetValue();
		SIZE_T32 numElements = buffer.ToSIZE_T32();

		if ( pElements.IsNull() )
		{
			PSX_PushError( "SubGeometryStream doesn't contain elements tag." );
			return EErrorCode::INVALID_FORMAT;
		}

		pElements = pElements->GetFirstChild();

		for ( SIZE_T32 i = 0; i < numElements; ++i )
		{
			if ( pElements.IsNull() )
			{
				PSX_PushError( "Missing SubGeometry elements." );
				return EErrorCode::INVALID_FORMAT;
			}

			// For each element, get indexoffset and numprimitives
			GeometrySubset newSubset;
			
			buffer = pElements->FindChild( PSX_String("IndexOffset") )->GetValue();
			newSubset.m_indicesOffset = buffer.ToSIZE_T32();
			buffer = pElements->FindChild( PSX_String("NumPrimitives") )->GetValue();
			newSubset.m_numPrimitives = buffer.ToSIZE_T32();

			m_desc.m_geometrySubsets.PushBack( newSubset );

			pElements = pElements->GetNextSibling();
		}

		return EErrorCode::OKAY;
	}

	RenderPassRenderInfo::RenderPassRenderInfo( void )
		: m_pInputLayout( PSX_NULL )
	{
		
	}

	RenderPassRenderInfo::~RenderPassRenderInfo( void )
	{
		if ( m_pInputLayout )
			m_pInputLayout->Release();

		for ( SIZE_T i = 0; i < m_vertexBuffers.GetSize(); ++i )
		{
			m_vertexBuffers[i]->Release();
		}

		m_vertexBuffers.Clear();
	}

	TechGeoRenderInfo::TechGeoRenderInfo( void )
	{

	}

	TechGeoRenderInfo::~TechGeoRenderInfo( void )
	{

	}

}